#include <list>

#include "brick.hpp"

#include "brick/echo.hpp"
#include "brick/uart.hpp"
#include "brick/pty.hpp"
#include "brick/shell.hpp"

namespace ha
{
    /*********************************************************************
     * @brief 初始化
     */
    bool factory_brick_t::init( const json_t& config )
    {
        if( ! config.is_object() )
        {
            llog_err( "<brick>", "ERROR: settings of bricks factory." );

            return false;
        }

        for( auto item : config.items() )
        {
            auto type = hude::utils::json_path_t::value< std::string >( item.value(), "type" );
            auto load = hude::utils::json_path_t::value< std::string >( item.value(), "load" );

            if( !type || !load )
            {
                llog_err( "<brick>", "ERROR: settings of %s factory.", item.key().c_str() );

                return false;
            }

            if( (*type) == "lib" )
            {
                // echo factory
                if( (*load) == "$(std)/echo" )
                {
                    auto cb = []( aio_t aio, const json_t& args ) -> pbrick_t
                    {
                        auto p = static_cast< brick_t* >( new brick::echo_t{ aio, args } );
                        return pbrick_t( p );
                    };

                    factorys_.emplace( item.key(), cb );

                    llog_nte( "<brick>", "SUCCESS: load factory( %s )", item.key().c_str() );
                } else

                // uart factory
                if( (*load) == "$(std)/uart" )
                {
                    auto cb = []( aio_t aio, const json_t& args ) -> pbrick_t
                    {
                        auto p = static_cast< brick_t* >( new brick::uart_t{ aio, args } );
                        return pbrick_t( p );
                    };

                    factorys_.emplace( item.key(), cb );

                    llog_nte( "<brick>", "SUCCESS: load factory( %s )", item.key().c_str() );
                } else

                // pty factory
                if( (*load) == "$(std)/pty" )
                {
                    auto cb = []( aio_t aio, const json_t& args ) -> pbrick_t
                    {
                        auto p = static_cast< brick_t* >( new brick::pty_t{ aio, args } );
                        return pbrick_t( p );
                    };

                    factorys_.emplace( item.key(), cb );

                    llog_nte( "<brick>", "SUCCESS: load factory( %s )", item.key().c_str() );
                } else

                // shell factory
                if( (*load) == "$(std)/shell" )
                {
                    auto cb = []( aio_t aio, const json_t& args ) -> pbrick_t
                    {
                        auto p = static_cast< brick_t* >( new brick::shell_t{ aio, args } );
                        return pbrick_t( p );
                    };

                    factorys_.emplace( item.key(), cb );

                    llog_nte( "<brick>", "SUCCESS: load factory( %s )", item.key().c_str() );
                } else

                // 查找是否有对应插件可载入
                {
                    factory_brick_t::plug_t plug{ *load };

                    if( ! plug )
                    {
                        llog_war( "<brick>", "ERROR: load plug: %s{ %s }", item.key().c_str(), (*load).c_str() );
                    } else {
                        factorys_.emplace( item.key(), plug );

                        llog_nte( "<brick>", "SUCCESS: load factory( %s : %s )", item.key().c_str(), (*load).c_str() );
                    }
                }
            }

        }

        return true;
    }

    /*********************************************************************
     * @brief 单例入口
     */
    factory_brick_t* factory_brick_t::single()
    {
        auto get = []() { return new factory_brick_t; };

        static std::unique_ptr< factory_brick_t > ptr( get() );

        return ptr.get();
    }

}  // namespace ha
